#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
主题: 读写JSON数据
问题: 你想读写JSON(JavaScript Object Notation)编码格式的数据。
提示 : 
"""

import json

data = {
    'name': 'ACME',
    'shares': 100,
    'price': 542.23
}

rfile = 'data.json'
wfile = '02_rw_json.json'


def recipe1():
    json_str = json.dumps(data, indent=4)       # indent 漂亮的格式化字符串后输出
    print(f"{json_str = }")
    print(f"{json.loads(json_str) = }")


def recipe2():
    with open(wfile, 'w') as f:
        json.dump(data, f)

    with open(rfile, 'r') as f:
        print(f"{json.load(f) = }")

def recipe3():
    print(json.dumps(False))
    d = {'a': True,
         'b': 'Hello',
         'c': None}
    print(f"{json.dumps(d) = }")

def recipe4():
    '''更加美观的方式输出'''
    from urllib.request import urlopen
    import json

    url = 'https://ng.ant.design/ngsw.json' # 'https://github.com/manifest.json'
    u = urlopen(url)
    resp = json.loads(u.read().decode('utf-8'))
    from pprint import pprint
    pprint(resp)

def recipe5():
    '''解码JSON数据并在一个OrderedDict中保留其顺序'''
    from collections import OrderedDict
    s = '{"name": "ACME", "price": 490.1, "shares": 50}'
    data = json.loads(s, object_pairs_hook=OrderedDict)
    print(f"{s = }")
    print(f"{data = }")

    # 一个JSON字典转换为一个Python对象
    data = json.loads(s, object_hook=JSONObject)
    print(f"{data = }")
    print(f"{data.name = }")
    print(f"{data.shares = }")
    print(f"{data.price = }")

def recipe6():
    '''对象实例通常并不是JSON可序列化的'''
    p = Point(2, 3)
    #json.dumps(p)       # TypeError: <__main__.Point object at 0x1006f2650> is not JSON serializable

    s = json.dumps(p, default=serialize_instance)
    print(f"{s = }")

    a = json.loads(s, object_hook=unserialize_object)
    print(f"{a = }")
    print(f"{a.x = }")
    print(f"{a.y = }")

def serialize_instance(obj):
    d = { '__classname__': type(obj).__name__}
    d.update(vars(obj))
    return d

def unserialize_object(d):
    clsname = d.pop('__classname__', None)
    if clsname:
        cls = classes[clsname]
        obj = cls.__new__(cls)
        for key, value in d.items():
            setattr(obj, key, value)
        return obj
    else:
        return d

class JSONObject:
    def __init__(self, d):
        self.__dict__ = d

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

# Dictionary mapping names to known classes
classes = {
    'Point': Point
}

def main():
    print('recipe1'.center(20, '*'))
    recipe1()
    print('recipe2'.center(20, '*'))
    recipe2()
    print('recipe3'.center(20, '*'))
    recipe3()
    print('recipe4'.center(20, '*'))
    recipe4()
    print('recipe5'.center(20, '*'))
    recipe5()
    print('recipe6'.center(20, '*'))
    recipe6()

if __name__ == '__main__':
    main()
